import {
  HttpStatus,
  HttpException,
  Controller,
  Query,
  Get,
  Put,
  Post,
  Body,
  Param,
  Logger,
  Delete,
  ParseIntPipe,
} from '@nestjs/common';
import { TaskService } from './task.services';
import {
  //ApiBearerAuth,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
import { PrismaService } from 'src/database/prisma.service';
import { PuppeteerDto } from './dto/puppeteer.dto';
import { CreateTaskDto } from './dto/create-task.dto';
import { PaginationDto } from './dto/list-tasks.dto';
import { TaskStatus } from 'src/prisma/client';
@ApiTags('task')
@Controller('task')
export class TaskController {
  constructor(
    private readonly appService: TaskService,
    private readonly prismaServer: PrismaService,
  ) {}
  @Get('list')
  @ApiOperation({ summary: 'List tasks' })
  @ApiResponse({ status: 200, description: '[task1,task2]' })
  async tasks(): Promise<string> {
    const value = await this.appService.list();
    if (!value) {
      return '';
    }
    return JSON.stringify(value);
  }

  @Get('pagination')
  @ApiOperation({ summary: 'pagination the tasks list' })
  @ApiResponse({
    status: 200,
    description: '{message:message,page,size,tasks:[]}',
  })
  async pagination(@Query() query: PaginationDto) {
    const { page, size, userId } = query; // Destructured with defaults applied
    const { total, tasks } = await this.appService.pagination(
      page,
      size,
      userId,
    );
    return {
      message: 'Tasks fetched successfully',
      page,
      size,
      total,
      tasks,
    };
  }
  @Post('puppeteer')
  async puppeteerTest(@Body() scrapData: PuppeteerDto): Promise<string> {
    Logger.log(scrapData);
    const rst = await this.appService.scrap(scrapData);

    return rst;
  }
  @Get('status/:id')
  getStatus(@Param('id') id: number): string {
    return `task get task status ID:${id}`;
  }

  @Get('start/:id')
  async start(@Param('id', ParseIntPipe) taskId: number): Promise<string> {
    Logger.log(`receive start start task ID:${taskId}`);

    const task = await this.prismaServer.getTask(taskId);
    if (!task) {
      Logger.error(`task ${taskId} not found!`);
      throw new HttpException(`Task ${taskId} not exist`, HttpStatus.NOT_FOUND);
    }
    if (task.platforms.length === 0 || task.keyword.trim() === '') {
      Logger.error(`task ${taskId} platform or keywords not initialized`);
      throw new HttpException(
        `Task ${taskId} platform or keyword not exist`,
        HttpStatus.NOT_FOUND,
      );
    }
    this.appService.performScraping(task);
    const resp = { status: 'success', message: 'start successfully' };
    return JSON.stringify(resp);
  }
  @Get('stop/:id')
  async stopTask(@Param('id', ParseIntPipe) id: number) {
    Logger.log(`stop task ${id}`);
    const updatedTask = await this.prismaServer.task
      .update({
        where: { id: id },
        data: {
          status: TaskStatus.COMPLETE,
          update_time: new Date(),
        },
      })
      .catch((error) => {
        if (error.code === 'P2025')
          throw new HttpException(`Task ${id} not found`, HttpStatus.NOT_FOUND);
        throw error;
      });
    return { message: `Task ${id} stopped`, data: updatedTask };
  }
  @Post()
  async create(@Body() taskData: CreateTaskDto): Promise<string> {
    Logger.log('create task', taskData);
    try {
      const platformIds = taskData.platforms?.map((v) => Number(v));
      const existingPlatforms = await this.prismaServer.platform.findMany({
        where: { id: { in: platformIds } },
      });
      if (existingPlatforms.length !== platformIds.length) {
        throw new Error('One or more platform IDs are invalid');
      }
      const task = {
        userId: taskData.userId,
        name: taskData.name,
        keyword: taskData.keyword,
        syncData: taskData.syncData,
        syncStrategy: taskData.syncStrategy,
        status: TaskStatus.CREATED,
      };
      const value = await this.prismaServer.task.create({
        data: {
          ...task,
          TaskPlatform: {
            create: platformIds.map((platformId) => ({
              platform: { connect: { id: platformId } },
            })),
          },
        },
      });

      return JSON.stringify(value);
    } catch (err) {
      throw new HttpException(
        'Exception Task Create failed',
        HttpStatus.BAD_REQUEST,
      );
    }
  }

  @Delete('/:id')
  async delete(@Param('id') id: number) {
    const value = await this.prismaServer.deleteTask(id);
    return JSON.stringify(value);
  }
  @Put('/:id')
  async updateTask(
    @Param('id', ParseIntPipe) id: number,
    @Body()
    updateData: {
      name?: string;
      keyword: string;
      status?: TaskStatus;
      syncStrategy?: boolean;
    },
  ) {
    Logger.log(`put task ${JSON.stringify(updateData)} id:${id}`);
    const updatedTask = await this.prismaServer.task
      .update({
        where: { id: id },
        data: {
          name: updateData.name,
          keyword: updateData.keyword,
          status: updateData.status,
          syncStrategy: updateData.syncStrategy,
          update_time: new Date(),
        },
      })
      .catch((error) => {
        if (error.code === 'P2025')
          throw new HttpException(`Task ${id} not found`, HttpStatus.NOT_FOUND);
        throw error;
      });
    return { message: `Task ${id} updated`, data: updatedTask };
  }
  @Put('/:id/update-platforms')
  async updateTaskPlatforms(
    @Param('id') id: string,
    @Body()
    updateData: { platformIds: number[]; name?: string; status?: TaskStatus },
  ) {
    const taskId = parseInt(id, 10);
    const updatedTask = await this.prismaServer
      .$transaction(async (prisma) => {
        const task = await prisma.task.findUnique({ where: { id: taskId } });
        if (!task)
          throw new HttpException(`Task ${id} not found`, HttpStatus.NOT_FOUND);
        await prisma.taskPlatform.deleteMany({ where: { taskId } });
        const taskPlatformData = updateData.platformIds.map((platformId) => ({
          taskId,
          platformId,
        }));
        await prisma.taskPlatform.createMany({
          data: taskPlatformData,
          skipDuplicates: true,
        });
        return await prisma.task.update({
          where: { id: taskId },
          data: {
            name: updateData.name,
            status: updateData.status,
            update_time: new Date(),
          },
        });
      })
      .catch((error) => {
        if (error.code === 'P2025')
          throw new HttpException(`Task ${id} not found`, HttpStatus.NOT_FOUND);
        if (error.code === 'P2003')
          throw new HttpException(
            `Invalid platformIds`,
            HttpStatus.BAD_REQUEST,
          );
        throw error;
      });
    return {
      message: `Task ${id} updated with new platforms`,
      data: updatedTask,
    };
  }
  @Put('/:id/remove-platform/:platformId')
  async removePlatformFromTask(
    @Param('id') id: string,
    @Param('platformId') platformId: string,
  ) {
    const taskId = parseInt(id, 10);
    const platId = parseInt(platformId, 10);
    Logger.log(`remove platform form task ${id} platform ${platId}`);
    return await this.appService.removePlatformFromTask(taskId, platId);
  }

  @Get('/:id')
  @ApiOperation({ summary: 'get task details' })
  @ApiResponse({ status: 200, description: '{id,name,platform...}' })
  async getTask(@Param('id') id: number): Promise<string> {
    const value = await this.prismaServer.getTask(id);
    if (value) {
      return JSON.stringify(value);
    } else {
      throw new HttpException(`Task ${id} not exists`, HttpStatus.NOT_FOUND);
    }
  }
}
